<template>
  <!-- 增改用户弹框 -->
  <hcDialog dialogWidth="90%" :dialogTitle="options.type === 'add' ? '新增工艺' : '编辑工艺'" :isVisable="options.show" @closeDialog="closeFun" @openDialog="openFun" top="2%">
    <div class="content">
      <el-form ref="formRef" :model="form" status-icon :rules="rules" class="i-f" label-width="6vw">
        <el-form-item prop="process_code" label="工艺编号">
          <el-input v-model="form.process_code" :readonly="options.type === 'edit'"> </el-input>
        </el-form-item>
        <el-form-item prop="process_name" label="工艺名称">
          <el-input v-model="form.process_name"> </el-input>
        </el-form-item>
        <el-form-item prop="enabled" label="是否可用">
          <el-select v-model="form.enabled" :style="{ width: '200px' }">
            <el-option label="可用" :value="true"></el-option>
            <el-option label="禁用" :value="false"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <div class="grape">
        <div class="chart">
          <div class="l-opera">
            <div class="title">工序节点</div>
            <div class="opera">
              <div class="opera-list">
                <div class="l-type t-ok">{{ t("common.normal") }}/OK工序节点</div>
                <div class="l-list">
                  <div class="item ok" v-for="item of operaOK" :key="item.operation" draggable="true" @dragstart="(event) => dragstart(event, item)">
                    <hcSvg name="cascader" :color="okColor"></hcSvg>
                    <div class="name">{{ item.name }}</div>
                  </div>
                </div>
              </div>
              <div class="opera-list">
                <div class="l-type t-ng">异常/NG工序节点</div>
                <div class="l-list">
                  <div class="item ng" v-for="item of operaNG" :key="item.operation" draggable="true" @dragstart="(event) => dragstart(event, item)">
                    <hcSvg name="cascader" :color="ngColor"></hcSvg>
                    <div class="name">{{ item.name }}</div>
                  </div>
                </div>
              </div>
            </div>
          </div>
          <div class="flow" ref="flowRef" @drop="dragHandle" @dragover="dragoverHandle" @dragenter="dragoverHandle">
            <div class="contain" ref="containRef"></div>
          </div>
        </div>
      </div>
      <div class="btns">
        <el-button type="primary" @click="saveDialog()">{{ t("common.saveText") }}</el-button>
        <el-button @click="closeFun">取消</el-button>
      </div>
    </div>
  </hcDialog>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import LogicFlow from "@logicflow/core";
import "@logicflow/core/lib/style/index.css";
import "@logicflow/extension/lib/style/index.css";
import { Menu, Control } from "@logicflow/extension";
import { getOperation, updateProcess, AddProcess } from "@/api/process";
import crect from "../nodeModel/crect.js";
import cdiamond from "../nodeModel/cdiamond.js";
import { ElMessage } from "element-plus";
import okline from "../nodeModel/okline.js";
import ngline from "../nodeModel/ngline.js";
import { useI18n } from "vue-i18n";
let { t } = useI18n();

const emit = defineEmits(["closeDialog"]);

const props = defineProps({
  options: {
    type: Object,
    default: () => {
      return {
        show: false,
        type: "add", // 用于判断是编辑还是删除 add edit
        data: null, // 当前编辑的用户
      };
    },
  },
});

let okColor = "#4078f2";
let ngColor = "#f22";

const formRef = ref();
const form = reactive({
  id: 0,
  process_code: "",
  process_name: "",
  enabled: true,
});
let containRef = ref();
let lf = null;

let operaOK = ref([
  // { operation: 1, name: "工序一", type: "c-rect", operation_type: "ok" },
  // { operation: 2, name: "工序二", type: "c-rect", operation_type: "ok" },
  // { operation: 3, name: "工序三", type: "c-rect", operation_type: "ok" },
  // { operation: 4, name: "工序四", type: "c-rect", operation_type: "ok" },
]);
let operaNG = ref([
  // { operation: 5, name: "工序一ng", type: "c-rect", operation_type: "ng" },
  // { operation: 6, name: "工序二ng", type: "c-rect", operation_type: "ng" },
  // { operation: 7, name: "工序三ng", type: "c-rect", operation_type: "ng" },
  // { operation: 8, name: "工序四ng", type: "c-rect", operation_type: "ng" },
]);

const rules = {
  process_code: [{ required: true, message: "请输入工艺编号", trigger: "blur" }],
  process_name: [{ required: true, message: "请输入工艺名称", trigger: "blur" }],
};

class RouteNode {
  process_id = 0;
  current_operation = 0;
  next_operation = 0;
  failed_operation = 0;
  return_operation = 0;
}

function saveDialog() {
  formRef.value.validate(async (valid) => {
    if (valid) {
      let route = [];
      let { nodes, edges } = lf.getGraphData();
      if (!edges || edges.length == 0 || !nodes || nodes.length == 0) {
        return ElMessage.warning("未创建工序关联关系");
      }
      for (let item of edges) {
        let { sourceNodeId, targetNodeId } = item;
        let text = item?.text?.value ?? "";
        let snode = nodes.find((n) => n.id == sourceNodeId);
        let tnode = nodes.find((n) => n.id == targetNodeId);
        let newRoute = new RouteNode();
        props.options.type === "edit" && (newRoute.process_id = options.data.process_id);
        let { operation: sop, operation_type: sot } = snode.properties;
        let { operation: top, operation_type: tot } = tnode.properties;
        newRoute.current_operation = sop;
        if (sot == "Normal") {
          if (tot == "Normal") {
            newRoute.next_operation = top;
          } else {
            newRoute.failed_operation = top;
          }
        } else {
          let ngNode = route.find((n) => n.current_operation == sop);
          if (ngNode) {
            ElMessage.error(snode.text.value + "节点配置有误");
            return;
          }
          newRoute.return_operation = top;
        }
        route.push(newRoute);
      }
      let nodeJson = JSON.stringify({ nodes, edges });
      let res = "";
      if (props.options.type === "edit") {
        res = await updateProcess({ ...form, flow_data: nodeJson, route });
      } else {
        res = await AddProcess({ ...form, flow_data: nodeJson, route });
      }
      if (res) {
        ElMessage.success("保存成功");
        emit("closeDialog", true);
      } else {
        ElMessage.error("保存失败");
      }
    }
  });
}

// 关闭弹框
const closeFun = () => {
  formRef.value?.resetFields();
  emit("closeDialog");
};

function openFun() {
  if (props.options.type === "edit") {
    for (let key in form) {
      form[key] = props.options.data[key];
    }
  }
  initLf();
}
const styleConfig = {
  style: {
    rect: {},
    polygon: {},
  },
};
function initLf() {
  lf = new LogicFlow({
    container: containRef.value,
    grid: true,
    ...styleConfig,
    plugins: [Menu, Control],
    edgeGenerator: (sourceNode, targetNode, currentEdge) => {
      // 起始节点类型 rect 时使用 自定义的边 custom-edge
      if (sourceNode.properties.operation_type == "Defective" || targetNode.properties.operation_type == "Defective") return "ngline";
    },
  });
  lf.register(ngline);
  lf.register(okline);
  lf.register(crect);

  lf.setDefaultEdgeType("okline");
  lf.register(cdiamond);
  lf.extension.menu.setMenuConfig({
    nodeMenu: [
      {
        text: t("common.delText"),
        callback(node) {
          lf.deleteNode(node.id);
        },
      },
    ], // 覆盖默认的节点右键菜单
    edgeMenu: false, // 删除默认的边右键菜单
  });
  if (props.options.type == "edit") {
    lf.render(JSON.parse(props.options.data.flow_data));
  } else {
    lf.render();
  }
}

const drag_key = "drag_key";
function dragstart(e, item) {
  e.dataTransfer.setData(drag_key, JSON.stringify(item));
}
function dragHandle(e) {
  let drayDataString = e.dataTransfer.getData(drag_key);
  if (!drayDataString) return;
  let { offsetX, offsetY } = e;
  let data = JSON.parse(drayDataString);
  let color = data.operation_type == "Normal" ? okColor : ngColor;
  let node = {
    id: data.id,
    x: offsetX,
    y: offsetY,
    text: data.name,
    type: data.type,
    properties: {
      operation: data.operation,
      operation_type: data.operation_type,
      style: {
        stroke: color,
      },
    },
  };
  lf.addNode(node);
}

function dragoverHandle(e) {
  e.preventDefault();
  e.stopPropagation();
  if (e.dataTransfer) e.dataTransfer.dropEffect = "copy";
}

async function getAllOpera() {
  let res = await getOperation();
  operaOK.value = [];
  operaNG.value = [];

  res?.items?.forEach((item) => {
    if (item.enabled) {
      item.operation_type == "Normal" &&
        operaOK.value.push({
          operation: item.id,
          name: item.operation_name,
          type: "c-rect",
          operation_type: "Normal",
        });
      item.operation_type == "Defective" &&
        operaNG.value.push({
          operation: item.id,
          name: item.operation_name,
          type: "c-rect",
          operation_type: "Defective",
        });
    }
  });
}
onMounted(() => {
  getAllOpera();
});
</script>
<style lang="scss" scoped>
.content {
  .i-f {
    display: flex;
  }
  .grape {
    width: 100%;
    height: 600px;
    margin: 10px 0;
    .chart {
      height: 100%;
      width: 100%;
      display: flex;
      .l-opera {
        width: 23%;
        border: 1px solid #bbb;
        .title {
          height: 30px;
          line-height: 30px;
          text-align: center;
          color: rgb(36, 132, 255);
        }
        .opera {
          width: 100%;
          height: calc(100% - 30px);
          overflow: auto;
          padding: 5px;
          .opera-list {
            .l-type {
              height: 30px;
              line-height: 30px;
              margin-bottom: 10px;
            }
            .t-ok {
              color: #4078f2;
              border-bottom: 1px dashed #4078f2;
            }
            .t-ng {
              color: #f22;
              border-bottom: 1px dashed #f22;
            }
            .l-list {
              width: 100%;
              display: flex;
              align-items: flex-start;
              align-content: flex-start;
              flex-wrap: wrap;
              .item {
                height: 40px;
                // width: 200px;
                padding: 0 5px;
                display: flex;
                align-items: center;
                justify-content: space-around;
                // border: 1px solid #ddd;
                margin-right: 10px;
                margin-bottom: 10px;
                .name {
                  min-width: 120px;
                }
                .img {
                  width: 40px;
                  height: 30px;
                }
              }
              .ok {
                border: 1px solid #4078f2;
              }
              .ng {
                border: 1px solid #f22;
              }
            }
          }
        }
      }
      .flow {
        margin-left: 10px;
        flex: 1;
        border: 1px solid #bbb;
        .contain {
          width: 100%;
          height: 100%;
        }
      }
    }
  }
  .btns {
    display: flex;
    justify-content: flex-end;
    padding: 0 20px;
  }
}
</style>
